#ifndef SCENE_EDITOR_FRAME_H
#define SCENE_EDITOR_FRAME_H

#include <QWidget>
#include <QTreeWidgetItem>
#include <QListWidgetItem>

#include <moveit/macros/class_forward.h>
#include <moveit/move_group_interface/move_group_interface.h>
#include <moveit/planning_scene_monitor/planning_scene_monitor.h>

#include <rviz/default_plugin/interactive_markers/interactive_marker.h>
#include <interactive_markers/interactive_marker_server.h>

namespace Ui
{
class SceneEditorFrame;
}

namespace moveit_rviz_plugin_scene_editor
{
class SceneEditorDisplay;

static const double LARGE_MESH_THRESHOLD = 10.0;
static const char* PACKAGE_NAME = "rviz_plugin_scene_editor";

class SceneEditorFrame : public QWidget
{
  friend class SceneEditorDisplay;
  Q_OBJECT

public:
  SceneEditorFrame(const SceneEditorFrame&) = delete;
  SceneEditorFrame(SceneEditorDisplay* pdisplay, rviz::DisplayContext* context, QWidget* parent = nullptr);
  ~SceneEditorFrame() override;

  void enable();
  void disable();

private Q_SLOTS:
  // Scene Objects tab
  void renameSceneObject();
  void combinationSceneObject();
  void unCombinationSceneObject();
  void saveAsPrefabSceneObject();
  void addPrefabSceneObject();
  void delPrefabSceneObject();
  void onCustomContextMenuRequested(const QPoint&);

  void clearScene();
  void publishScene();
  void publishSceneIfNeeded();
  void setLocalSceneEdited(bool dirty = true);
  bool isLocalSceneDirty() const;
  void addSceneObject();
  void removeSceneObject();
  void selectedCollisionObjectChanged();
  void objectPoseValueChanged(double value);
  void objectSizeValueChanged(double value);
  void collisionObjectChanged(QListWidgetItem* item);
  void imProcessFeedback(visualization_msgs::InteractiveMarkerFeedback& feedback);
  void copySelectedCollisionObject();
  void exportGeometryAsTextButtonClicked();
  void importGeometryFromTextButtonClicked();

  void lockPosition();

private:
  void loadPrefab();
  bool createPrefabSceneObject(const boost::filesystem::path& scene_file_path);
  // Scene objects tab
  void updateCollisionObjectPose(bool update_marker_position);
  void updateCollisionObjectSize(bool update_marker_position);
  void createSceneInteractiveMarker();
  void renameCollisionObject(QListWidgetItem* item);
  void attachDetachCollisionObject(QListWidgetItem* item);
  void populateCollisionObjectsList();
  void computeImportGeometryFromText(const std::string& path);
  void computeExportGeometryAsText(const std::string& path);
  visualization_msgs::InteractiveMarker createObjectMarkerMsg(const collision_detection::World::ObjectConstPtr& obj);

  void setItemSelectionInList(const std::string& item_name, bool selection, QListWidget* list);
  shapes::ShapePtr loadMeshResource(const std::string& url);
  void sceneUpdate(planning_scene_monitor::PlanningSceneMonitor::SceneUpdateType update_type);
  void updateSceneMarkers(float wall_dt, float /*ros_dt*/);

private:
  ros::NodeHandle nh_;
  ros::Publisher planning_scene_publisher_;
  ros::Publisher planning_scene_world_publisher_;

  std::vector<std::pair<std::string, bool> > known_collision_objects_;
  long unsigned int known_collision_objects_version_;

  std::map<std::string, collision_detection::World::ObjectPtr> prefab_objects_;

  std::shared_ptr<rviz::InteractiveMarker> scene_marker_;

private:
  union
  {
    unsigned int lock_position_val;  // 锁定位置，方便在界面移动
    struct
    {
      unsigned int lock_position_x : 1;  // 0x01 lock_position_x;
      unsigned int lock_position_y : 1;  // 0x02 lock_position_y;
      unsigned int lock_position_z : 1;  // 0x04 lock_position_z;
    };
  };

  SceneEditorDisplay* planning_display_;
  rviz::DisplayContext* context_;
  Ui::SceneEditorFrame* ui_;
};
}  // namespace moveit_rviz_plugin_scene_editor

#endif  // SCENE_EDITOR_FRAME_H
